<?php
/**
 * @package techniv-bb.tcnv-fw
 * @version $Id$
 * @copyright © Techniv 2011
 * @license <http://opensource.org/licenses/gpl-3.0.html> GNU General Public License - 3.0
 */


/**
 * @ignore
 */
if(!defined("IN_PHPBB")){
	exit;
}

define('IN_TCNV_FW', true);

/**
 * TcnvMaster is the master contener of TcnvFW.
 * @author Techniv
 * @copyright © Techniv 2011
 */
class TcnvMaster {
//<editor-fold defaultstate="collapsed" desc="Constantes">
	private static $installs_file = "installs";
//</editor-fold>
    
    /** @var string */
    private $root_path;
	/** @var string */
	private $self_path;
	
	private $intalled_mod;




	/** @var TcnvSQL */
	private $sql;
	
	//phpBB Session
	/** @var user */
	private $user;
	/** @var auth */
	private $auth;
	/** @var cache */
	private $cache;
	/** @var template */
	private $template;

	
	private static $noLoadMod = array();

	private function __construct() {
        define("INTCNV", true);
        
		$this->self_path = dirname(__FILE__).'/';
        $this->root_path = $this->self_path.'../';
		
		
		$this->initTcnv();
		$this->load_install_list();
		$this->initMods();
		$this->save_install_list();
    }
	
	/**
	 * Check and get and element of the phpBB session.
	 * @param mixed $element
	 */
	private function getting_phpBB_session_element($element){
		$class = new ReflectionClass($element);
		switch ($class->name){
			case 'user' :
				$this->user = &$element;
				break;
			case 'auth' :
				$this->auth = &$elment;
				break;
			case 'cache' :
				$this->cache = &$element;
				break;
			case 'template' :
				$this->template = &$element;
				break;
		}
	}
	
	private function initTcnv() {
		
		$includePath = array(
			$this->self_path,
			$this->self_path.'interfaces/',
			$this->self_path.'listeners/',
		);
		self::includeFolder($includePath);
		$this->initAnnotationEngine();
		
		// SGBD config load
		require $this->root_path.'config.php';
		
		$sql_impl_class = 'TcnvSQL_'.$dbms;
		$sql_impl_file = $this->self_path.'sql/'.$sql_impl_class.'.php';

		try {
			if(!file_exists($sql_impl_file)) throw new TcnvException ("Fichier introuvable: $sql_impl_file");
			include_once $sql_impl_file;
			
			if(!class_exists($sql_impl_class)) throw new TcnvException("Classe introuvable: $sql_impl_class");
			$this->sql = new $sql_impl_class();
			
			$this->sql->setConnection($dbhost, $dbuser, $dbpasswd, $dbname, $table_prefix, $dbport);
		} catch (Exception $ex){
			if(defined('DEBUG')) echo "[Tcnv] Echec de chargement de la classe $sql_impl_class.<br>".
									$ex->getMessage();
		}
		
		
	}
	
	public function initAnnotationEngine() {
		require_once $this->self_path.'lib/addendum/annotations.php';
		$annotation_path = $this->self_path.'annotations/';
		self::includeFolder($annotation_path);
	}

	
	private function initMods() {
		$modPath = $this->self_path.'/mods/';
		$modDir = opendir($modPath);
		while($item = readdir($modDir)){
			if(!in_array($item, array('.','..')) 
					&& is_dir($modPath.$item) 
					&& !in_array(strtoupper($item), self::$noLoadMod)){
				$this->loadMod($item);
			}
		}
	}


	public static function noLoadMod($modname){
		self::$noLoadMod[] = strtoupper($modname);
	}
	
	private function loadMod($modname){
		// Chargement du fichier du module
		$modPath = $this->self_path.'mods/'.$modname.'/';

		self::includeFolder($modPath);
		if(!class_exists($modname)){
			if(defined("DEBUG")){ echo "[Tcnv] Mod $modname non trouvéà $mod_file";}
			return;
		}
		
		$mod_class = new ReflectionAnnotatedClass($modname);
		$mod_class->newInstance();
		
		// Traitement des attributs.
		$mob_properties = $mod_class->getProperties();
		
		$add_tpl = array();

		foreach ($mob_properties as $property) {
			$property instanceof ReflectionAnnotatedProperty;
			if($property->hasAnnotation('TplVar')){
				$annotation = $property->getAnnotation('TplVar');
				$property->setAccessible(true);
				$key = strtoupper($property->name);
				$value = $property->getValue(null);
				
				if(isset($annotation->value) && $annotation->value != ''){
					$key = strtoupper($annotation->value);
				}
				$add_tpl[$key] = $value;
			}
			if($property->hasAnnotation("Datasource")){
				$property->setAccessible(true);
				$property->setValue(null, $this->sql);
			}
		}

		TcnvTemplateSync::add_tpl_vars($add_tpl);
		
		
		// Traitement des méthodes.
		$interceptors = array(
			InterceptPostRow::$_name,
			InterceptBlocAssignement::$_name,
			InterceptVarsAssignement::$_name,
			InterceptPosting::$_name,
			InterceptParseDisplayMessage::$_name,
			InterceptDisplay::$_name,
		);
		$intercepting = array();
		foreach ($interceptors as $value) {
			$intercepting[$value] = array();
		}
		
		$mod_methods = $mod_class->getMethods();
		foreach ($mod_methods as $method){
			$method instanceof ReflectionAnnotatedMethod;
			$annotations = $method->getAnnotations();
			
			if($method->hasAnnotation(Install::$_name) 
					&& !in_array($mod_class->name, $this->intalled_mod)){
				$result = $method->invoke($mod_class->newInstance(), null);
				if($result){
					$this->intalled_mod[] = $mod_class->name;
				}
			}
			
			foreach ($annotations as $annotation){
			
				if(isset($intercepting[$annotation->annotation_name])){
					$annotation_value = $annotation->value;
					$intercepting[$annotation->annotation_name][] = array(
						'method'			=> $method,
						'annotation_value'	=> $annotation_value
					);
				}
			}
		}
		
		foreach ($intercepting as $key => $value) {
			TcnvListner::add_intercepting($key, $value);
		}
	}

	
// <editor-fold defaultstate="collapsed" desc="SINGLETON & GETTERS PHPBB">
    
	//SINGLETON & GETTERS PHPBB
	
	/** @var TcnvExt */
	private static $instance;

	/**
	 * @return TcnvMaster instence unique de la classe
	 */
	public static function getInstance(){
		if(!isset (self::$instance)){
			self::$instance = new TcnvMaster();
		}
		if(func_num_args()>0){
			for($i=0; $i<func_num_args(); $i++){
				$arg = func_get_arg($i);
				self::getInstance()->getting_phpBB_session_element($arg);
			}
		}
		
		return self::$instance;
	}
	
	/** @return user */
	public function getUser() {
		return $this->user;
	}

	/** @return auth */
	public function getAuth() {
		return $this->auth;
	}

	/** @return cache */
	public function getCache() {
		return $this->cache;
	}

	/** @return template */
	public function getTemplate() {
		return $this->template;
	}

	public function getRequestParam($name = null) {
		$query_string = $this->user->page['query_string'];
		$couple = split("&", $query_string);
		$params = array();
		foreach ($couple as $value) {
			$param = split("=", $value);
			$params[$param[0]] = $param[1];
		}
		if(isset ($name)){
			if (isset($params[$name])) return $params[$name];
			else return null;
		}
		return $params;
	}
	
	public function get_user_groups(){
		$user_id = $this->user->data['user_id'];
		$table_name = "user_group";
		
		$datasource = $this->sql;
		
		$sql = "SELECT group_id FROM ".$datasource->prefixTable($table_name)." "
				."WHERE user_id=$user_id && user_pending=0";
		$result_set = $datasource->query_array($sql);
		$result = array();
		foreach ($result_set as $value) {
			$result[] = $value['group_id'];
		}
		return $result;
	}

// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="UTILS">
    public static function includeFolder($folder) {
		if(is_array($folder)){
			foreach ($folder as $item) {
				self::includeFolder($item);
			}
			return;
		}
		$dir = opendir($folder);
		while ($file = readdir($dir)){
			if(is_file($folder.$file) &&  preg_match("#^.*\.php$#", $file)){
				require_once $folder.$file;
			}
		}
	}
	
	public function load_install_list(){
		if(is_file($this->self_path.self::$installs_file)){
			$file = fopen($this->self_path.self::$installs_file, 'r');
			$content = fgets($file);
			fclose($file);
			$this->intalled_mod = unserialize($content);
		} else {
			$this->intalled_mod = array();
		}
	}
	
	public function save_install_list() {
		$serialise = serialize($this->intalled_mod);
		try {
			$file = fopen($this->self_path.self::$installs_file, 'w');
			fwrite($file, $serialise);
			fclose($file);
		} catch (Exception $exc) {
			trigger_error("Can't write file ".$this->self_path.self::$installs_file);
			trigger_error($exc->getTraceAsString());
		}

	}
// </editor-fold>
}

?>
